package com.jagochan.module.rbac.sys_menu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jagochan.common.result.ResultUtils;
import com.jagochan.module.rbac.sys_menu.domain.SysMenu;
import com.jagochan.module.rbac.sys_menu.domain.vo.MenuTreeAssignVo;
import com.jagochan.module.rbac.sys_menu.mapper.SysMenuMapper;
import com.jagochan.module.rbac.sys_menu.service.SysMenuService;
import com.jagochan.module.rbac.sys_role_menu.service.SysRoleMenuService;
import com.jagochan.module.rbac.sys_user.domain.SysUser;
import com.jagochan.module.rbac.sys_user.service.SysUserService;
import com.jagochan.module.rbac.sys_user_role.service.SysUserRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    private final SysUserService sysUserService;
    private final SysUserRoleService sysUserRoleService;
    private final SysRoleMenuService sysRoleMenuService;

    @Override
    public List<SysMenu> listMenuTree() {
        // 查询菜单列表
        List<SysMenu> menuList = lambdaQuery().orderByAsc(SysMenu::getOrderNum).list();
        // 组装为树形结构
        return makeTree(menuList, 0L);
    }

    @Override
    public List<SysMenu> listParentMenuTree() {
        // 查询【目录0】和【菜单1】类型的菜单，不查询【按钮2】
        List<SysMenu> menuList = lambdaQuery()
                .in(SysMenu::getType, List.of("0", "1"))
                .orderByAsc(SysMenu::getOrderNum)
                .list();

        menuList.add(SysMenu.builder()
                .title("顶级菜单")
                .label("顶级菜单")
                .parentId(-1L) // 顶级菜单的父菜单parentId等于-1
                .menuId(0L)
                .value(0L)
                .build());
        return makeTree(menuList, -1L);
    }

    /**
     * 根据角色ID和用户ID查询菜单树
     */
    @Override
    public MenuTreeAssignVo listTreeMenuByRoleAndUser(String roleId, String userId) {
        // 1. 查询当前用户拥有的菜单列表
        SysUser user = sysUserService.getById(userId);
        if (user == null) return null;
        List<SysMenu> menuList;
        if (user.getIsAdmin() != null && "1".equals(user.getIsAdmin())) { // 当前用户是超级管理员
            menuList = list();
        } else { // 当前用户是普通用户（仅查询当前用户拥有的菜单）
            menuList = listMenuByUserId(userId);
        }

        // 2. 根据roleId查询菜单列表（根据roleId查看当前角色拥有的菜单是哪些）
        List<Long> menuIdList = sysRoleMenuService.listMenuIdsByRoleIds(List.of(Long.valueOf(roleId)));

        // 3. 返回结果
        MenuTreeAssignVo vo = new MenuTreeAssignVo();
        vo.setMenuList(makeTree(menuList, 0L));
        vo.setCheckedList(menuIdList);
        return vo;
    }

    /**
     * 根据用户ID查询菜单列表
     */
    @Override
    public List<SysMenu> listMenuByUserId(String userId) {
        // 根据用户ID查询用户拥有的角色ID列表【sys_user_role】
        List<Long> roleIdList = sysUserRoleService.listRoleIdsByUserId(Long.valueOf(userId));
        // 根据角色ID列表查询该角色对应的菜单ID列表【sys_role_menu】
        List<Long> menuIdList = sysRoleMenuService.listMenuIdsByRoleIds(roleIdList);
        // 根据菜单ID列表查询菜单详细数据列表
        return lambdaQuery().in(SysMenu::getMenuId, menuIdList).orderByAsc(SysMenu::getOrderNum).list();
    }

    public static List<SysMenu> makeTree(List<SysMenu> menuList, Long pid) {
        return Optional.ofNullable(menuList).orElse(new ArrayList<>())
                .stream()
                .filter(item -> item != null && item.getParentId().equals(pid))
                .map(item -> {
                    SysMenu menu = new SysMenu();
                    BeanUtils.copyProperties(item, menu);
                    menu.setLabel(item.getTitle());
                    menu.setValue(item.getMenuId());
                    // 递归调用查找下级
                    List<SysMenu> children = makeTree(menuList, item.getMenuId());
                    menu.setChildren(children);
                    return menu;
                }).collect(Collectors.toList());
    }
}